/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009-2017 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
* or LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.webservices;
import com.sun.enterprise.deployment.*;
import com.sun.xml.ws.api.server.*;
import com.sun.xml.ws.transport.http.servlet.ServletAdapter;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.deployment.versioning.VersioningUtils;
import org.jvnet.hk2.annotations.Service;
import com.sun.enterprise.container.common.spi.WebServiceReferenceManager;
import com.sun.xml.ws.api.FeatureConstructor;
import com.sun.xml.ws.resources.ModelerMessages;
import javax.inject.Inject;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.InitialContext;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
import javax.xml.ws.soap.MTOMFeature;
import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.RespectBindingFeature;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.spi.WebServiceFeatureAnnotation;
import java.io.*;
import java.lang.reflect.*;
import java.lang.annotation.Annotation;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.security.PrivilegedActionException;
import java.net.URL;
/**
* This class acts as a service to resolve the
* </code>javax.xml.ws.WebServiceRef</code> references
* and also <code>javax.xml.ws.WebServiceContext</code>
* Whenever a lookup is done from GlassfishNamingManagerImpl
* these methods are invoked to resolve the references
*
* @author Bhakti Mehta
*/
@Service
public class WebServiceReferenceManagerImpl implements WebServiceReferenceManager {
@Inject
private ServerEnvironment serverEnv;
protected Logger logger = LogUtils.getLogger();
public Object getWSContextObject() {
return new WebServiceContextImpl();
}
public Object resolveWSReference(ServiceReferenceDescriptor desc, Context context)
throws NamingException {
//Taken from NamingManagerImpl.getClientServiceObject
Class serviceInterfaceClass = null;
Object returnObj = null;
WsUtil wsUtil = new WsUtil();
//Implementation for new lookup element in WebserviceRef
InitialContext iContext = new InitialContext();
if( desc.hasLookupName()) {
return iContext.lookup(desc.getLookupName());
}
try {
WSContainerResolver.set(desc);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
serviceInterfaceClass = cl.loadClass(desc.getServiceInterface());
resolvePortComponentLinks(desc);
javax.xml.rpc.Service serviceDelegate = null;
javax.xml.ws.Service jaxwsDelegate = null;
Object injValue = null;
if( desc.hasGeneratedServiceInterface() || desc.hasWsdlFile() ) {
String serviceImplName = desc.getServiceImplClassName();
if(serviceImplName != null) {
Class serviceImplClass = cl.loadClass(serviceImplName);
serviceDelegate = (javax.xml.rpc.Service) serviceImplClass.newInstance();
} else {
// The target is probably a post JAXRPC-1.1- based service;
// If Service Interface class is set, check if it is indeed a subclass of Service
// initiateInstance should not be called if the user has given javax.xml.ws.Service itself
// as the interface through DD
if(javax.xml.ws.Service.class.isAssignableFrom(serviceInterfaceClass) &&
!javax.xml.ws.Service.class.equals(serviceInterfaceClass) ) {
// OK - the interface class is indeed the generated service class; get an instance
injValue = initiateInstance(serviceInterfaceClass, desc);
} else {
// First try failed; Try to get the Service class type from injected field name
// and from there try to get an instance of the service class
// I assume the at all inejction target are expecting the SAME service
// interface, therefore I take the first one.
if (desc.isInjectable()) {
InjectionTarget target = desc.getInjectionTargets().iterator().next();
Class serviceType = null;
if (target.isFieldInjectable()) {
java.lang.reflect.Field f = target.getField();
if(f == null) {
String fName = target.getFieldName();
Class targetClass = cl.loadClass(target.getClassName());
try {
f = targetClass.getDeclaredField(fName);
} catch(java.lang.NoSuchFieldException nsfe) {}// ignoring exception
}
if(f != null) {
serviceType = f.getType();
}
}
if (target.isMethodInjectable()) {
Method m = target.getMethod();
if(m == null) {
String mName = target.getMethodName();
Class targetClass = cl.loadClass(target.getClassName());
try {
m = targetClass.getDeclaredMethod(mName);
} catch(java.lang.NoSuchMethodException nsfe) {}// ignoring exception
}
if (m != null && m.getParameterTypes().length==1) {
serviceType = m.getParameterTypes()[0];
}
}
if (serviceType!=null){
Class loadedSvcClass = cl.loadClass(serviceType.getCanonicalName());
injValue = initiateInstance(loadedSvcClass, desc);
}
}
}
// Unable to get hold of generated service class -> try the Service.create avenue to get a Service
if(injValue == null) {
// Here create the service with WSDL (overridden wsdl if wsdl-override is present)
// so that JAXWS runtime uses this wsdl @ runtime
javax.xml.ws.Service svc =
javax.xml.ws.Service.create((new WsUtil()).privilegedGetServiceRefWsdl(desc),
desc.getServiceName());
jaxwsDelegate = new JAXWSServiceDelegate(desc, svc, cl);
}
}
if( desc.hasHandlers() ) {
// We need the service's ports to configure the
// handler chain (since service-ref handler chain can
// optionally specify handler-port association)
// so create a configured service and call getPorts
javax.xml.rpc.Service configuredService =
wsUtil.createConfiguredService(desc);
Iterator ports = configuredService.getPorts();
wsUtil.configureHandlerChain
(desc, serviceDelegate, ports, cl);
}
// check if this is a post 1.1 web service
if(javax.xml.ws.Service.class.isAssignableFrom(serviceInterfaceClass)) {
// This is a JAXWS based webservice client;
// process handlers and mtom setting
// moved test for handlers into wsUtil, in case
// we have to add system handler
javax.xml.ws.Service service =
(injValue != null ?
(javax.xml.ws.Service) injValue : jaxwsDelegate);
if (service != null) {
// Now configure client side handlers
wsUtil.configureJAXWSClientHandlers(service, desc);
}
// the requested resource is not the service but one of its port.
if (injValue!=null && desc.getInjectionTargetType()!=null) {
Class requestedPortType = service.getClass().getClassLoader().loadClass(desc.getInjectionTargetType());
ArrayList<WebServiceFeature> wsFeatures = getWebServiceFeatures(desc);
if (wsFeatures.size() >0) {
injValue = service.getPort(requestedPortType,wsFeatures.toArray(new WebServiceFeature[wsFeatures.size()]));
} else {
injValue = service.getPort(requestedPortType);
}
}
}
} else {
// Generic service interface / no WSDL
QName serviceName = desc.getServiceName();
if( serviceName == null ) {
// ServiceFactory API requires a service-name.
// However, 109 does not allow getServiceName() to be
// called, so it's ok to use a dummy value.
serviceName = new QName("urn:noservice", "servicename");
}
ServiceFactory serviceFac = ServiceFactory.newInstance();
serviceDelegate = serviceFac.createService(serviceName);
}
// Create a proxy for the service object.
// Get a proxy only in jaxrpc case because in jaxws the service class is not
// an interface any more
InvocationHandler handler = null;
if(serviceDelegate != null) {
handler = new ServiceInvocationHandler(desc, serviceDelegate, cl);
returnObj = Proxy.newProxyInstance
(cl, new Class[] { serviceInterfaceClass }, handler);
} else if(jaxwsDelegate != null) {
returnObj = jaxwsDelegate;
} else if(injValue != null) {
returnObj = injValue;
}
} catch(PrivilegedActionException pae) {
logger.log(Level.WARNING, LogUtils.EXCEPTION_THROWN, pae);
NamingException ne = new NamingException();
ne.initCause(pae.getCause());
throw ne;
} catch(Exception e) {
logger.log(Level.WARNING, LogUtils.EXCEPTION_THROWN, e);
NamingException ne = new NamingException();
ne.initCause(e);
throw ne;
} finally {
WSContainerResolver.unset();
}
return returnObj;
}
private Object initiateInstance(Class svcClass, ServiceReferenceDescriptor desc)
throws Exception {
//TODO BM if JBI needs this reenable it
/*com.sun.enterprise.webservice.ServiceRefDescUtil descUtil =
new com.sun.enterprise.webservice.ServiceRefDescUtil();
descUtil.preServiceCreate(desc);*/
WsUtil wsu = new WsUtil();
URL wsdlFile = wsu.privilegedGetServiceRefWsdl(desc);
/* TODO BM resolve catalog
// Check if there is a catalog for this web service client
// If so resolve the catalog entry
String genXmlDir;
if(desc.getBundleDescriptor().getApplication() != null) {
genXmlDir = desc.getBundleDescriptor().getApplication().getGeneratedXMLDirectory();
if(!desc.getBundleDescriptor().getApplication().isVirtual()) {
String subDirName = desc.getBundleDescriptor().getModuleDescriptor().getArchiveUri();
genXmlDir += (File.separator+subDirName.replaceAll("\\.", "_"));
}
} else {
// this is the case of an appclient being run as class file from command line
genXmlDir = desc.getBundleDescriptor().getModuleDescriptor().getArchiveUri();
}
File catalogFile = new File(genXmlDir,
desc.getBundleDescriptor().getDeploymentDescriptorDir() +
File.separator + "jax-ws-catalog.xml");
if(catalogFile.exists()) {
wsdlFile = wsu.resolveCatalog(catalogFile, desc.getWsdlFileUri(), null);
} */
Object obj = null ;
java.lang.reflect.Constructor cons = svcClass.getConstructor
(new Class[]{java.net.URL.class,
javax.xml.namespace.QName.class});
try {
obj =
cons.newInstance(wsdlFile, desc.getServiceName());
} catch (Exception e) {
/*
* If WSDL URL is not accessible over http, trying to get an instance via
* reflection results in InvocationTargetException. If InvocationTargetException
* is thrown,then catch the exception and generate wsdl in generated xml directory
* of the application being deployed.
*/
if (e instanceof InvocationTargetException) {
URL optionalWsdlURL = generateWsdlFile(desc);
if (optionalWsdlURL == null)
throw e;
obj = cons.newInstance(optionalWsdlURL, desc.getServiceName());
}
}
/*TODO BM if jbi needs this reenable it
descUtil.postServiceCreate();
*/
return obj;
}
/**
* This method returns the location where optional wsdl file will be generated.
* The directory will be a directory having same name as WebService name inside
* application's generated xml directory. The name of the wsdl file will be
* wsdl.xml e.g. if application name is test and service name is Translator,
* then the location of wsdl will be
* $Glassfish_home/domains/domain1/generated/xml/test/Translator/wsdl.xml
*
* @param desc ServiceReferenceDescriptor
* @return optional wsdl file location
*/
private File getOptionalWsdlLocation(ServiceReferenceDescriptor desc) {
File generatedXmlDir = serverEnv.getApplicationGeneratedXMLPath();
return new File(new File(new File(generatedXmlDir,
VersioningUtils.getRepositoryName(desc.getBundleDescriptor().getApplication()
.getRegistrationName())), desc.getServiceLocalPart()), "wsdl.xml");
}
private void createParentDirs(File optionalWsdlLocation) throws IOException {
File parent = optionalWsdlLocation.getParentFile();
mkDirs(parent);
}
private URL generateWsdlFile(ServiceReferenceDescriptor desc) throws IOException {
/*
* Following piece of code is basically a copy-paste from JAXWSServlet's
* doGet method (line 230) and from com.sun.xml.ws.transport.http.servlet.HttpAdapter's
* publishWSDL method (line 587).This piece of code is not completely clear to me,
* what I have understood so far is, during WSEndPoint creation on line 267 in
* WSServletContextListener, com.sun.xml.ws.server.EndPointFactory.create (line 116)
* method is invoked where ServiceDocumentImpl instance is created, which is later
* being fetched here to generate wsdl. When serviceDefinition.getPrimary() is
* invoked, basically it returns the reference to wsdl document marked as primary
* wsdl inside ServiceDefinition. Probably we can directly fetch this wsdl
* but for now I will go with the way it has been implemented in HttpAdapter.
*/
File optionalWsdl = getOptionalWsdlLocation(desc);
/*
* Its possible that in a given application there are more than one Filter/Servlet
* with loadOnStartup=1 having WebServiceRef annotation,or WebServiceRef
* annotation is used at multiple places within the same Filter/Servlet,
* in which case, when processing is going on for second filter/servlet
* or annotation referring to the same web service, then wsdl file has
* already been generated at this point in time and there is no need to
* generate it again.
*/
if (optionalWsdl.exists())
return optionalWsdl.toURI().toURL();
createParentDirs(optionalWsdl);
ServletAdapter targetEndpoint = getServletAdapter(desc);
if (targetEndpoint == null)
return null;
ServiceDefinition serviceDefinition = targetEndpoint.getServiceDefinition();
Iterator wsdlnum = serviceDefinition.iterator();
SDDocument wsdlDocument = null;
while (wsdlnum.hasNext()) {
SDDocument xsdnum = (SDDocument) wsdlnum.next();
if (xsdnum == serviceDefinition.getPrimary()) {
wsdlDocument = xsdnum;
break;
}
}
if (wsdlDocument == null)
return null;
OutputStream outputStream = null;
try {
outputStream = new BufferedOutputStream(new FileOutputStream(optionalWsdl));
PortAddressResolver portAddressResolver = targetEndpoint
.getPortAddressResolver(getBaseAddress(desc.getWsdlFileUrl()));
DocumentAddressResolver resolver = targetEndpoint.getDocumentAddressResolver(portAddressResolver);
wsdlDocument.writeTo(portAddressResolver, resolver, outputStream);
} finally {
if (outputStream != null)
outputStream.close();
}
return optionalWsdl.toURI().toURL();
}
/**
* Returns ServletAdapter instance holding wsdl for the WebService being referred
* in WebServiceRef annotation.
*
* @param desc ServiceReferenceDescriptor
* @return ServletAdapter instance having wsdl contents.
*/
private ServletAdapter getServletAdapter(ServiceReferenceDescriptor desc) {
WebBundleDescriptor webBundle = null;
WebServicesDescriptor webServicesDescriptor = null;
/*
* If flow has reached to this part of the code,then in all likelihood,
* the wsdl is available under the context root of the a web application
* and hence the BundleDescriptor being referred in ServiceReferenceDescriptor
* is an instance of WebBundleDescriptor.
*/
if (desc.getBundleDescriptor() instanceof WebBundleDescriptor) {
webBundle = ((WebBundleDescriptor) desc.getBundleDescriptor());
} else {
/*
* If above assumption is not true, then make one last attempt to fetch
* all required params from the wsdl url stored in ServiceReferenceDescriptor.
*/
return getServletAdapterBasedOnWsdlUrl(desc);
}
/*
* Get WebServicesDescriptor from WebBundleDescriptorImpl, Since we are
* dealing with WebServiceRef annotation here, WebServicesDescriptor ought to have
* reference to WebService in question. WebServicesDescriptor is never null as it
* is being initialized at class level in BundleDescriptor.
*/
WebServicesDescriptor wsDesc = webBundle.getWebServices();
assert wsDesc != null;
/*
* WebService name is being fetched by invoking getServiceLocalPart()
* on ServiceReferenceDescriptor. ServiceLocalPart is set when WebServiceClient
* annotated class is processed inside
* org.glassfish.webservices.connector.annotation.handlers.WebServiceRefHandler's
* processAWsRef call (line 339). WebServiceClient annotation have name param pointing
* to webservice in question.
*/
assert desc.getServiceLocalPart() != null;
WebService webService = wsDesc.getWebServiceByName(desc.getServiceLocalPart());
/*
* If an unlikely event when there is no associated webService or desc.getServiceLocalPart()
* itself is null, then fall back on fetching ServletAdapter based on wsdl url.
*/
if (webService == null)
return getServletAdapterBasedOnWsdlUrl(desc);
String contextRoot = webBundle.getContextRoot();
String webSevicePath = null;
String publishingContext = null;
/*
* Iterate over all associated WebServiceEndPoints for this WebService
* and break when condition specified in if block is met. This is the same
* condition based on which wsdl url is set in first place for this
* ServiceReferenceDescriptor and hence this must hold true in this context too.
*/
for (WebServiceEndpoint endpoint : webService.getEndpoints()) {
if (desc.getServiceName().equals(endpoint.getServiceName())
&& desc.getServiceNamespaceUri().equals(endpoint.getWsdlService().getNamespaceURI())) {
String endPointAddressURI = endpoint.getEndpointAddressUri();
if (endPointAddressURI == null || endPointAddressURI.length() == 0)
return null;
webSevicePath = endPointAddressURI.startsWith("/") ? endPointAddressURI : ("/" + endPointAddressURI);
publishingContext = "/" + endpoint.getPublishingUri() + "/" + webService.getWsdlFileUri();
Adapter adapter = JAXWSAdapterRegistry.getInstance()
.getAdapter(contextRoot, webSevicePath, publishingContext);
return adapter instanceof ServletAdapter ? (ServletAdapter) adapter : null;
}
}
return null;
}
/**
* This method basically is a fall back mechanism to fetch required
* parameters from wsdl url stored in ServiceReferenceDescriptor. The flow reaches
* here only in case where required parameters could not be fetched
* from WebBundleDescriptor.
*
* @param desc ServiceReferenceDescriptor
* @return ServletAdapter instance having wsdl contents.
*/
private ServletAdapter getServletAdapterBasedOnWsdlUrl(ServiceReferenceDescriptor desc) {
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO, LogUtils.SERVLET_ADAPTER_BASED_ON_WSDL_URL,
new Object[]{desc.getServiceLocalPart(), desc.getWsdlFileUrl()});
}
URL wsdl = desc.getWsdlFileUrl();
String wsdlPath = wsdl.getPath().trim();
if (!wsdlPath.contains(WebServiceEndpoint.PUBLISHING_SUBCONTEXT))
return null;
/*
* WsdlPath indeed contains the WebServiceEndpoint.PUBLISHING_SUBCONTEXT,
* e.g.assuming that context root is test and Service name is Translator
* then wsdl url must be in the following format :
* /test/Translator/__container$publishing$subctx/null?wsdl
*/
String contextRootAndPath = wsdlPath.substring(1,
wsdlPath.indexOf(WebServiceEndpoint.PUBLISHING_SUBCONTEXT) - 1); // test/Translator
if (!(contextRootAndPath.length() > 0))
return null;
String[] contextRootAndPathArray = contextRootAndPath.split("/"); // {test, Translator}
if (contextRootAndPathArray.length != 2)
return null;
if (contextRootAndPathArray[0] == null)
return null;
String contextRoot = "/" + contextRootAndPathArray[0]; // /test
if (contextRootAndPathArray[1] == null)
return null;
String webSevicePath = "/" + contextRootAndPathArray[1]; // /Translator
String urlPattern = wsdlPath.substring(contextRoot.length());
Adapter adapter = JAXWSAdapterRegistry.getInstance()
.getAdapter(contextRoot, webSevicePath, urlPattern);
return adapter instanceof ServletAdapter ? (ServletAdapter) adapter : null;
}
private static String getBaseAddress(URL wsdlUrl) {
return wsdlUrl.getProtocol() + "://" + wsdlUrl.getHost() + ":" + wsdlUrl.getPort();
}
private void mkDirs(File f) {
if (!f.mkdirs() && logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, LogUtils.DIR_EXISTS, f);
}
}
private ArrayList<WebServiceFeature> getWebServiceFeatures(ServiceReferenceDescriptor desc) {
/**
* JAXWS 2.2 enables @MTOM, @Addressing @RespectBinding
* on WebServiceRef
* If these are present use the
* Service(url,wsdl,features) constructor
*/
ArrayList<WebServiceFeature> wsFeatures = new ArrayList<WebServiceFeature>();
if (desc.isMtomEnabled()) {
wsFeatures.add( new MTOMFeature(true,desc.getMtomThreshold())) ;
}
com.sun.enterprise.deployment.Addressing add = desc.getAddressing();
if (add != null) {
wsFeatures.add( new AddressingFeature(
add.isEnabled(),add.isRequired(),getResponse(add.getResponses()))) ;
}
com.sun.enterprise.deployment.RespectBinding rb = desc.getRespectBinding();
if (rb != null) {
wsFeatures.add( new RespectBindingFeature(rb.isEnabled())) ;
}
Map<Class<? extends Annotation>, Annotation> otherAnnotations =
desc.getOtherAnnotations();
Iterator it = otherAnnotations.values().iterator();
while(it.hasNext()){
wsFeatures.add(getWebServiceFeatureBean((Annotation)it.next()));
}
return wsFeatures;
}
private AddressingFeature.Responses getResponse(String s) {
if (s != null) {
return AddressingFeature.Responses.valueOf(AddressingFeature.Responses.class,s);
} else return AddressingFeature.Responses.ALL;
}
private void resolvePortComponentLinks(ServiceReferenceDescriptor desc)
throws Exception {
// Resolve port component links to target endpoint address.
// We can't assume web service client is running in same VM
// as endpoint in the intra-app case because of app clients.
//
// Also set port-qname based on linked port's qname if not
// already set.
for(Iterator iter = desc.getPortsInfo().iterator(); iter.hasNext();) {
ServiceRefPortInfo portInfo = (ServiceRefPortInfo) iter.next();
if( portInfo.isLinkedToPortComponent() ) {
WebServiceEndpoint linkedPortComponent =
portInfo.getPortComponentLink();
// XXX-JD we could at this point try to figure out the
// endpoint-address from the ejb wsdl file but it is a
// little complicated so I will leave it for post Beta2
if( !(portInfo.hasWsdlPort()) ) {
portInfo.setWsdlPort(linkedPortComponent.getWsdlPort());
}
}
}
}
private WebServiceFeature getWebServiceFeatureBean(Annotation a) {
WebServiceFeatureAnnotation wsfa = a.annotationType().getAnnotation(WebServiceFeatureAnnotation.class);
Class<? extends WebServiceFeature> beanClass = wsfa.bean();
WebServiceFeature bean;
Constructor ftrCtr = null;
String[] paramNames = null;
for (Constructor con : beanClass.getConstructors()) {
FeatureConstructor ftrCtrAnn = (FeatureConstructor) con.getAnnotation(FeatureConstructor.class);
if (ftrCtrAnn != null) {
if (ftrCtr == null) {
ftrCtr = con;
paramNames = ftrCtrAnn.value();
} else {
throw new WebServiceException(ModelerMessages.RUNTIME_MODELER_WSFEATURE_MORETHANONE_FTRCONSTRUCTOR(a, beanClass));
}
}
}
if (ftrCtr == null) {
throw new WebServiceException(ModelerMessages.RUNTIME_MODELER_WSFEATURE_NO_FTRCONSTRUCTOR(a, beanClass));
}
if (ftrCtr.getParameterTypes().length != paramNames.length) {
throw new WebServiceException(ModelerMessages.RUNTIME_MODELER_WSFEATURE_ILLEGAL_FTRCONSTRUCTOR(a, beanClass));
}
try {
Object[] params = new Object[paramNames.length];
for (int i = 0; i < paramNames.length; i++) {
Method m = a.annotationType().getDeclaredMethod(paramNames[i]);
params[i] = m.invoke(a);
}
bean = (WebServiceFeature) ftrCtr.newInstance(params);
} catch (Exception e) {
throw new WebServiceException(e);
}
return bean;
}
}